#include <iostream>
#include "common.h"
#include "NesCartridge.h"
#include "mapper/MapperFactory.h"

NesCartridge::NesCartridge(Famicom* fc) :famicom(fc)
{
}

NesCartridge::~NesCartridge()
{
}

void NesCartridge::Reset() {
	if (this->mRom == nullptr)
		return;
	this->mRom->mapper->Reset();
	famicom->fcPPU->SwitchMirroring(mRom->isVmirroring ? Mirror::VERTICAL : Mirror::HORIZONTAL);
}

famicon_rom_t* NesCartridge::GetRom() {
	return mRom;
}

bool NesCartridge::IsLoadedRom() {
	return mLoadedrom;
}


uint8_t NesCartridge::PRG_num()
{
	return mRom->prg16kbCount;
}

/// <summary>
/// 
/// </summary>
void NesCartridge::ReleaseFcRom(famicon_rom_t* rom) {
	if (rom->prgrom != nullptr)
		delete[] rom->prgrom;
	if (rom->chrrom != nullptr)
		delete[] rom->chrrom;
	if (rom->mapper != nullptr)
		delete rom->mapper;
	delete rom;
}
/// <summary>
///
/// </summary>
/// <param name="rom"></param>
/// <param name="size"></param>
/// <returns></returns>
int NesCartridge::LoadRom(famicon_rom_t* rom) {

	this->mRom = rom;
	this->mLoadedrom = rom != nullptr;
	return true;
}

void NesCartridge::Save(SaveBundle* bundle)
{
	if (this->mRom != nullptr && this->mRom->mapper != nullptr)
		this->mRom->mapper->Save(bundle);
}

void NesCartridge::Restore(SaveBundle* bundle)
{
	if (this->mRom != nullptr && this->mRom->mapper != nullptr)
		this->mRom->mapper->Restore(bundle);
}

/// <summary>
/// 验证文件头 (已废弃)
/// </summary>
/// <param name="header"></param>
/// <param name="hsize"></param>
/// <param name="psize"></param>
/// <returns></returns>
bool NesCartridge::CreateFcRom(famicon_rom_t** rom, void* data, size_t size)
{
	if (size < 16)
		return false;

	NesHeader* romhead = static_cast<NesHeader*>(data);


	uint8_t* nesdata = static_cast<uint8_t*>(data) + 16;

	romhead->nes[3] = '\0';
	if (strcmp((char const*)romhead->nes, "NES") != 0) {
		return false;
	}

	famicon_rom_t* fcrom = new famicon_rom_t;

	fcrom->prg16kbCount = romhead->PRGBankCount;
	fcrom->chr8kbCount = romhead->CHRBankCount;

	//fcrom->prgrom = nullptr;
	//fcrom->chrrom = nullptr;

	fcrom->isVmirroring = (romhead->flag1) & 0x1;
	fcrom->hasBatteryBacked = (romhead->flag1 >> 1) & 0x1;
	fcrom->hasTrainer = (romhead->flag1 >> 2) & 0x1;
	fcrom->isFourScreen = (romhead->flag1 >> 3) & 0x1;

	fcrom->version = (romhead->flag2 >> 2) & 0x3;


	uint8_t map = romhead->flag1 >> 4;
	map |= (romhead->flag2 & 0xf0);

	fcrom->mapperNumber = map;

	fcrom->prgRomSize = fcrom->prg16kbCount * 16 * 1024;
	fcrom->chrRomSize = fcrom->chr8kbCount * 8 * 1024;

	fcrom->size = fcrom->prgRomSize + fcrom->chrRomSize;
	if (size - 16 != fcrom->size)
		goto failed;

	fcrom->isChrRAM = fcrom->chr8kbCount == 0;

	fcrom->prgrom = new uint8_t[fcrom->prgRomSize];

	memcpy_s(fcrom->prgrom, fcrom->prgRomSize, nesdata, fcrom->prgRomSize);

	if (!fcrom->isChrRAM) {
		fcrom->chrrom = new uint8_t[fcrom->chrRomSize];
		memcpy(fcrom->chrrom, nesdata + fcrom->prgRomSize, fcrom->chrRomSize);
	}
	else {
		fcrom->chrrom = new uint8_t[8192];
		fcrom->chrRomSize = 8192;
		fcrom->chr8kbCount = 1;
	}

	fcrom->mapper = MapperFactory::Factory(famicom, fcrom);
	if (fcrom->mapper == nullptr) {
		goto failed;
	}
	//mLoadedrom = true;
	*rom = fcrom;

	DebugPrintf("Mapper:%d prg16kbCount:%d chr8kbCount:%d version:%d hasBatteryBacked:%d hasTrainer:%d\n",
		fcrom->mapperNumber,
		fcrom->prg16kbCount,
		fcrom->chr8kbCount,
		fcrom->version,
		fcrom->hasBatteryBacked,
		fcrom->hasTrainer);

	return true;
failed:
	DebugPrintf("加载失败");
	this->ReleaseFcRom(fcrom);
	return false;
}